/******************************************************************************* * Copyright (c) 2004, 2013 Richard Hoefter and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Richard Hoefter (richard.hoefter@web.de) - initial API and implementation, bug 95297, bug 97051, bug 128103, bug 201180, bug 161354, bug 313386 * IBM Corporation - nlsing and incorporating into Eclipse, bug 108276, bug 124210, bug 161845, bug 177833 * Nikolay Metchev (N.Metchev@teamphone.com) - bug 108276 * Ryan Fong (rfong@trapezenetworks.com) - bug 201143 *******************************************************************************/ package org.eclipse.ant.internal.ui.datatransfer; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeMap; import java.util.TreeSet; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; import org.eclipse.ant.internal.core.IAntCoreConstants; import org.eclipse.ant.internal.ui.AntUIPlugin; import org.eclipse.ant.internal.ui.model.IAntModelConstants; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.widgets.Shell; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.xml.sax.SAXException; /** * Creates build.xml file. */ public class BuildFileCreator { protected static final String IMPORT_BUILDFILE_PROCESSING_TARGET = "eclipse.ant.import"; //$NON-NLS-1$ protected static final String WARNING = " WARNING: Eclipse auto-generated file." + ExportUtil.NEWLINE + //$NON-NLS-1$ " Any modifications will be overwritten."; //$NON-NLS-1$ protected static final String NOTE = " To include a user specific buildfile here, " + //$NON-NLS-1$ "simply create one in the same" + ExportUtil.NEWLINE + //$NON-NLS-1$ " directory with the processing instruction " + //$NON-NLS-1$ "<?" + IMPORT_BUILDFILE_PROCESSING_TARGET + "?>" + ExportUtil.NEWLINE + //$NON-NLS-1$ //$NON-NLS-2$ " as the first entry and export the buildfile again. "; //$NON-NLS-1$ protected static String BUILD_XML = "build.xml"; //$NON-NLS-1$ protected static String JUNIT_OUTPUT_DIR = "junit"; //$NON-NLS-1$ protected static boolean CHECK_SOURCE_CYCLES = true; protected static boolean CREATE_ECLIPSE_COMPILE_TARGET = true; private Document doc; private Element root; private IJavaProject project; private String projectName; private String projectRoot; private Map<String, String> variable2valueMap; private Shell shell; private Set<String> visited = new TreeSet<>(); // record used subclasspaths private Node classpathNode; /** * Constructor. Please prefer {@link #createBuildFiles(Set, Shell, IProgressMonitor)} if you do not want call the various createXXX() methods * yourself. * * @param project * create buildfile for this project * @param shell * parent instance for dialogs */ public BuildFileCreator(IJavaProject project, Shell shell) throws ParserConfigurationException { this.project = project; this.projectName = project.getProject().getName(); this.projectRoot = ExportUtil.getProjectRoot(project); this.variable2valueMap = new LinkedHashMap<>(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); this.doc = dbf.newDocumentBuilder().newDocument(); this.shell = shell; } /** * Create buildfile for given projects. * * @param projects * create buildfiles for these <code>IJavaProject</code> objects * @param shell * parent instance for dialogs * @return project names for which buildfiles were created * @throws InterruptedException * thrown when user cancels task */ public static List<String> createBuildFiles(Set<IJavaProject> projects, Shell shell, IProgressMonitor pm) throws JavaModelException, ParserConfigurationException, TransformerConfigurationException, TransformerException, IOException, CoreException, InterruptedException { List<String> res = new ArrayList<>(); try { createBuildFilesLoop(projects, shell, pm, res); } finally { if (pm != null) { pm.done(); } } return res; } private static void createBuildFilesLoop(Set<IJavaProject> projects, Shell shell, IProgressMonitor pm, List<String> res) throws CoreException, ParserConfigurationException, JavaModelException, TransformerConfigurationException, TransformerFactoryConfigurationError, TransformerException, UnsupportedEncodingException { // determine files to create/change List<IFile> files = new ArrayList<>(); for (Iterator<IJavaProject> iter = projects.iterator(); iter.hasNext();) { IJavaProject currentProject = iter.next(); IFile file = currentProject.getProject().getFile(BuildFileCreator.BUILD_XML); files.add(file); } // trigger checkout Set<IFile> confirmedFiles = ExportUtil.validateEdit(shell, files); SubMonitor localmonitor = SubMonitor.convert(pm, DataTransferMessages.AntBuildfileExportPage_0, confirmedFiles.size()); try { Iterator<IJavaProject> iter = projects.iterator(); while (iter.hasNext()) { IJavaProject currentProject = iter.next(); IFile file = currentProject.getProject().getFile(BuildFileCreator.BUILD_XML); if (!confirmedFiles.contains(file)) { continue; } localmonitor.setTaskName(NLS.bind(DataTransferMessages.BuildFileCreator_generating_buildfile_for, currentProject.getProject().getName())); BuildFileCreator instance = new BuildFileCreator(currentProject, shell); instance.createRoot(); instance.createImports(); EclipseClasspath classpath = new EclipseClasspath(currentProject); if (CHECK_SOURCE_CYCLES) { SourceAnalyzer.checkCycles(currentProject, classpath, shell); } instance.createClasspaths(classpath); instance.createInit(classpath.srcDirs, classpath.classDirs, classpath.inclusionLists, classpath.exclusionLists); instance.createClean(classpath.classDirs); instance.createCleanAll(); instance.createBuild(classpath.srcDirs, classpath.classDirs, classpath.inclusionLists, classpath.exclusionLists); instance.createBuildRef(); if (CREATE_ECLIPSE_COMPILE_TARGET) { instance.addInitEclipseCompiler(); instance.addBuildEclipse(); } instance.createRun(); instance.addSubProperties(currentProject, classpath); instance.createProperty(); // write build file String xml = ExportUtil.toString(instance.doc); InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8")); //$NON-NLS-1$ if (file.exists()) { file.setContents(is, true, true, null); } else { file.create(is, true, null); } if (localmonitor.isCanceled()) { return; } localmonitor.worked(1); res.add(instance.projectName); } } finally { if (!localmonitor.isCanceled()) { localmonitor.done(); } } } /** * Add property tag. */ public void createProperty() { // read debug options from Eclipse settings boolean source = JavaCore.GENERATE.equals(project.getOption(JavaCore.COMPILER_SOURCE_FILE_ATTR, true)); boolean lines = JavaCore.GENERATE.equals(project.getOption(JavaCore.COMPILER_LINE_NUMBER_ATTR, true)); boolean vars = JavaCore.GENERATE.equals(project.getOption(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR, true)); List<String> debuglevel = new ArrayList<>(); if (source) { debuglevel.add("source"); //$NON-NLS-1$ } if (lines) { debuglevel.add("lines"); //$NON-NLS-1$ } if (vars) { debuglevel.add("vars"); //$NON-NLS-1$ } if (debuglevel.size() == 0) { debuglevel.add("none"); //$NON-NLS-1$ } variable2valueMap.put("debuglevel", ExportUtil.toString(debuglevel, ",")); //$NON-NLS-1$ //$NON-NLS-2$ // "Generated .class files compatibility" String target = project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true); variable2valueMap.put("target", target); //$NON-NLS-1$ // "Compiler compliance level" // String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true); // "Source compatibility" String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true); variable2valueMap.put("source", sourceLevel); //$NON-NLS-1$ // <property name="x" value="y"/> boolean first = true; Node node = root.getFirstChild(); for (Iterator<String> iterator = variable2valueMap.keySet().iterator(); iterator.hasNext();) { String key = iterator.next(); String value = variable2valueMap.get(key); Element prop = doc.createElement("property"); //$NON-NLS-1$ prop.setAttribute(IAntCoreConstants.NAME, key); prop.setAttribute(IAntCoreConstants.VALUE, value); if (first) { first = false; } else { node = node.getNextSibling(); } node = root.insertBefore(prop, node); } // <property environment="env"/> Element env = doc.createElement("property"); //$NON-NLS-1$ env.setAttribute("environment", "env"); //$NON-NLS-1$ //$NON-NLS-2$ root.insertBefore(env, root.getFirstChild()); } /** * Create project tag. */ public void createRoot() { // <project name="hello" default="build" basedir="."> root = doc.createElement("project"); //$NON-NLS-1$ root.setAttribute(IAntCoreConstants.NAME, projectName); root.setAttribute(IAntCoreConstants.DEFAULT, "build"); //$NON-NLS-1$ root.setAttribute("basedir", "."); //$NON-NLS-1$ //$NON-NLS-2$ doc.appendChild(root); // <!-- warning --> Comment comment = doc.createComment(WARNING + ExportUtil.NEWLINE + NOTE); doc.insertBefore(comment, root); } /** * Find buildfiles in projectroot directory and automatically import them. */ public void createImports() { // <import file="javadoc.xml"/> File dir = new File(projectRoot); FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File acceptDir, String name) { return name.endsWith(".xml"); //$NON-NLS-1$ } }; File[] files = dir.listFiles(filter); if (files == null) { return; } for (int i = 0; i < files.length; i++) { // import file if it is an XML document with marker comment as first // child File file = files[i]; Document docCandidate; try { docCandidate = ExportUtil.parseXmlFile(file); NodeList nodes = docCandidate.getChildNodes(); for (int j = 0; j < nodes.getLength(); j++) { Node node = nodes.item(j); if (node instanceof ProcessingInstruction && IMPORT_BUILDFILE_PROCESSING_TARGET.equals(((ProcessingInstruction) node).getTarget().trim())) { Element element = doc.createElement("import"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.FILE, file.getName()); root.appendChild(element); break; } } } catch (ParserConfigurationException e) { AntUIPlugin.log("invalid XML file not imported: " + file.getAbsolutePath(), e); //$NON-NLS-1$ } catch (SAXException e) { AntUIPlugin.log("invalid XML file not imported: " + file.getAbsolutePath(), e); //$NON-NLS-1$ } catch (IOException e) { AntUIPlugin.log("invalid XML file not imported: " + file.getAbsolutePath(), e); //$NON-NLS-1$ } } } /** * Create classpath tags. */ public void createClasspaths(EclipseClasspath classpath) throws JavaModelException { createClasspaths(null, project, classpath); } /** * Create classpath tags. Allows to specify ID. * * @param pathId * specify id, if null project name is used */ public void createClasspaths(String pathId, IJavaProject currentProject, EclipseClasspath classpath) throws JavaModelException { if (currentProject == null) { AntUIPlugin.log("project is not loaded in workspace: " + pathId, null); //$NON-NLS-1$ return; } // <path id="hello.classpath"> // <pathelement location="${hello.location}/classes"/> // <pathelement location="${hello.location}/x.jar"/> // <path refid="${goodbye.classpath}"/> // </path> Element element = doc.createElement("path"); //$NON-NLS-1$ String pathid = pathId; if (pathid == null) { pathid = currentProject.getProject().getName() + ".classpath"; //$NON-NLS-1$ } element.setAttribute("id", pathid); //$NON-NLS-1$ visited.add(pathid); variable2valueMap.putAll(classpath.variable2valueMap); for (Iterator<String> iter = ExportUtil.removeDuplicates(classpath.rawClassPathEntries).iterator(); iter.hasNext();) { String entry = iter.next(); if (EclipseClasspath.isProjectReference(entry)) { Element pathElement = doc.createElement("path"); //$NON-NLS-1$ IJavaProject referencedProject = EclipseClasspath.resolveProjectReference(entry); if (referencedProject == null) { AntUIPlugin.log("project is not loaded in workspace: " + pathid, null); //$NON-NLS-1$ continue; } String refPathId = referencedProject.getProject().getName() + ".classpath"; //$NON-NLS-1$ pathElement.setAttribute("refid", refPathId); //$NON-NLS-1$ element.appendChild(pathElement); if (visited.add(refPathId)) { createClasspaths(null, referencedProject, new EclipseClasspath(referencedProject)); // recursion } } else if (EclipseClasspath.isUserLibraryReference(entry) || EclipseClasspath.isLibraryReference(entry)) { addUserLibrary(element, entry); } else if (EclipseClasspath.isUserSystemLibraryReference(entry)) { if (pathid.endsWith(".bootclasspath")) { //$NON-NLS-1$ addUserLibrary(element, entry); } } else if (EclipseClasspath.isJreReference(entry)) { if (pathid.endsWith(".bootclasspath")) { //$NON-NLS-1$ addJre(element); } } else { // prefix with ${project.location} String prefix = IAntCoreConstants.EMPTY_STRING; if (!entry.startsWith("${") && // no variable ${var}/classes //$NON-NLS-1$ !projectName.equals(currentProject.getProject().getName())) // not main project { String currentProjectRoot = ExportUtil.getProjectRoot(currentProject); entry = ExportUtil.getRelativePath(entry, currentProjectRoot); if (!new Path(entry).isAbsolute()) { prefix = "${" + currentProject.getProject().getName() + ".location}/"; //$NON-NLS-1$ //$NON-NLS-2$ } } Element pathElement = doc.createElement("pathelement"); //$NON-NLS-1$ String path = ExportUtil.getRelativePath(prefix + entry, projectRoot); pathElement.setAttribute(IAntModelConstants.ATTR_LOCATION, path); element.appendChild(pathElement); } } addToClasspathBlock(element); } private void addUserLibrary(Element element, String entry) { // add classpath reference Element pathElement = doc.createElement("path"); //$NON-NLS-1$ IClasspathContainer container = EclipseClasspath.resolveUserLibraryReference(entry); String name = ExportUtil.removePrefixAndSuffix(entry, "${", "}"); //$NON-NLS-1$ //$NON-NLS-2$ pathElement.setAttribute("refid", name); //$NON-NLS-1$ element.appendChild(pathElement); // add classpath if (visited.add(entry)) { Element userElement = doc.createElement("path"); //$NON-NLS-1$ userElement.setAttribute("id", name); //$NON-NLS-1$ IClasspathEntry entries[] = container.getClasspathEntries(); for (int i = 0; i < entries.length; i++) { String jarFile = entries[i].getPath().toString(); // use ECLIPSE_HOME variable for library jars if (EclipseClasspath.isLibraryReference(entry)) { IPath home = JavaCore.getClasspathVariable("ECLIPSE_HOME"); //$NON-NLS-1$ if (home != null && home.isPrefixOf(entries[i].getPath())) { variable2valueMap.put("ECLIPSE_HOME", home.toString()); //$NON-NLS-1$ jarFile = "${ECLIPSE_HOME}" + jarFile.substring(home.toString().length()); //$NON-NLS-1$ } else if (!new File(jarFile).exists() && jarFile.startsWith('/' + projectName) && new File(projectRoot, jarFile.substring(('/' + projectName).length())).exists()) { // workaround that additional jars are stored with // leading project root in container object, although // they are relative and indeed correctly stored in // build.properties (jars.extra.classpath) jarFile = jarFile.substring(('/' + projectName).length() + 1); } } jarFile = ExportUtil.getRelativePath(jarFile, projectRoot); Element userPathElement = doc.createElement("pathelement"); //$NON-NLS-1$ userPathElement.setAttribute(IAntModelConstants.ATTR_LOCATION, jarFile); userElement.appendChild(userPathElement); } addToClasspathBlock(userElement); } } /** * Add JRE to given classpath. * * @param element * classpath tag */ private void addJre(Element element) { // <fileset dir="${java.home}/lib" includes="*.jar"/> // <fileset dir="${java.home}/lib/ext" includes="*.jar"/> Element pathElement = doc.createElement("fileset"); //$NON-NLS-1$ pathElement.setAttribute(IAntCoreConstants.DIR, "${java.home}/lib"); //$NON-NLS-1$ pathElement.setAttribute("includes", "*.jar"); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(pathElement); pathElement = doc.createElement("fileset"); //$NON-NLS-1$ pathElement.setAttribute(IAntCoreConstants.DIR, "${java.home}/lib/ext"); //$NON-NLS-1$ pathElement.setAttribute("includes", "*.jar"); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(pathElement); } private void addToClasspathBlock(Element element) { // remember node to insert all classpaths at same location if (classpathNode == null) { classpathNode = root.appendChild(element); } else { classpathNode = classpathNode.getNextSibling(); classpathNode = root.insertBefore(element, classpathNode); } } /** * Add properties of sub-projects to internal properties map. */ public void addSubProperties(IJavaProject subproject, EclipseClasspath classpath) throws JavaModelException { for (Iterator<IJavaProject> iterator = ExportUtil.getClasspathProjectsRecursive(subproject).iterator(); iterator.hasNext();) { IJavaProject subProject = iterator.next(); String location = subProject.getProject().getName() + ".location"; //$NON-NLS-1$ // add subproject properties to variable2valueMap String subProjectRoot = ExportUtil.getProjectRoot(subProject); String relativePath = ExportUtil.getRelativePath(subProjectRoot, projectRoot); variable2valueMap.put(location, relativePath); variable2valueMap.putAll(classpath.variable2valueMap); } } /** * Create init target. Creates directories and copies resources. * * @param srcDirs * source directories to copy resources from * @param classDirs * classes directories to copy resources to */ public void createInit(List<String> srcDirs, List<String> classDirs, List<List<String>> inclusionLists, List<List<String>> exclusionLists) { // <target name="init"> // <mkdir dir="classes"/> // </target> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "init"); //$NON-NLS-1$ List<String> classDirsUnique = ExportUtil.removeDuplicates(classDirs); for (Iterator<String> iterator = classDirsUnique.iterator(); iterator.hasNext();) { String classDir = iterator.next(); if (!classDir.equals(".") && !EclipseClasspath.isReference(classDir)) { //$NON-NLS-1$ Element pathElement = doc.createElement("mkdir"); //$NON-NLS-1$ pathElement.setAttribute(IAntCoreConstants.DIR, classDir); element.appendChild(pathElement); } } root.appendChild(element); createCopyResources(srcDirs, classDirs, element, inclusionLists, exclusionLists); } private void createCopyResources(List<String> srcDirs, List<String> classDirs, Element element, List<List<String>> inclusionLists, List<List<String>> exclusionLists) { // Check filter for copying resources String filter = project.getOption(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true); StringTokenizer tokenizer = new StringTokenizer(filter, ","); //$NON-NLS-1$ ArrayList<String> filters = new ArrayList<>(); while (tokenizer.hasMoreTokens()) { filters.add(tokenizer.nextToken()); } filters.add("*.java"); //$NON-NLS-1$ // prefix filters with wildcard for (int i = 0; i < filters.size(); i++) { String item = filters.get(i).trim(); if (item.equals("*")) //$NON-NLS-1$ { // everything is excluded from copying return; } filters.set(i, "**/" + item); //$NON-NLS-1$ } // <copy todir="classes" includeemptydirs="false"> // <fileset dir="src" excludes="**/*.java"/> // </copy> for (int i = 0; i < srcDirs.size(); i++) { String srcDir = srcDirs.get(i); String classDir = classDirs.get(i); if (!EclipseClasspath.isReference(classDir)) { Element copyElement = doc.createElement("copy"); //$NON-NLS-1$ copyElement.setAttribute("todir", classDir); //$NON-NLS-1$ copyElement.setAttribute("includeemptydirs", "false"); //$NON-NLS-1$ //$NON-NLS-2$ Element filesetElement = doc.createElement("fileset"); //$NON-NLS-1$ filesetElement.setAttribute(IAntCoreConstants.DIR, srcDir); List<String> inclusions = inclusionLists.get(i); List<String> exclusions = exclusionLists.get(i); for (String inclusion : inclusions) { Element includeElement = doc.createElement("include"); //$NON-NLS-1$ includeElement.setAttribute(IAntCoreConstants.NAME, inclusion); filesetElement.appendChild(includeElement); } for (String exclusion : filters) { Element excludeElement = doc.createElement("exclude"); //$NON-NLS-1$ excludeElement.setAttribute(IAntCoreConstants.NAME, exclusion); filesetElement.appendChild(excludeElement); } for (String exclusion : exclusions) { Element excludeElement = doc.createElement("exclude"); //$NON-NLS-1$ excludeElement.setAttribute(IAntCoreConstants.NAME, exclusion); filesetElement.appendChild(excludeElement); } copyElement.appendChild(filesetElement); element.appendChild(copyElement); } } } /** * Create clean target. * * @param classDirs * classes directories to delete */ public void createClean(List<String> classDirs) { // <target name="clean"> // <delete dir="classes"/> // </target> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "clean"); //$NON-NLS-1$ List<String> classDirUnique = ExportUtil.removeDuplicates(classDirs); for (Iterator<String> iterator = classDirUnique.iterator(); iterator.hasNext();) { String classDir = iterator.next(); if (!classDir.equals(".") && //$NON-NLS-1$ !EclipseClasspath.isReference(classDir)) { Element deleteElement = doc.createElement("delete"); //$NON-NLS-1$ deleteElement.setAttribute(IAntCoreConstants.DIR, classDir); element.appendChild(deleteElement); } } root.appendChild(element); // <target name="clean"> // <delete> // <fileset dir="." includes="**/*.class"/> // </delete> // </target> if (classDirs.contains(".")) //$NON-NLS-1$ { Element deleteElement = doc.createElement("delete"); //$NON-NLS-1$ Element filesetElement = doc.createElement("fileset"); //$NON-NLS-1$ filesetElement.setAttribute(IAntCoreConstants.DIR, "."); //$NON-NLS-1$ filesetElement.setAttribute("includes", "**/*.class"); //$NON-NLS-1$ //$NON-NLS-2$ deleteElement.appendChild(filesetElement); element.appendChild(deleteElement); } } /** * Create cleanall target. */ public void createCleanAll() throws JavaModelException { // <target name="cleanall" depends="clean"> // <ant antfile="build.xml" dir="${hello.location}" inheritAll="false" target="clean"/> // </target> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "cleanall"); //$NON-NLS-1$ element.setAttribute("depends", "clean"); //$NON-NLS-1$ //$NON-NLS-2$ List<IJavaProject> subProjects = ExportUtil.getClasspathProjectsRecursive(project); for (Iterator<IJavaProject> iterator = subProjects.iterator(); iterator.hasNext();) { IJavaProject subProject = iterator.next(); Element antElement = doc.createElement("ant"); //$NON-NLS-1$ antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$ antElement.setAttribute(IAntCoreConstants.DIR, "${" + subProject.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("target", "clean"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(antElement); } root.appendChild(element); } /** * Create build target. * * @param srcDirs * source directories of mainproject * @param classDirs * class directories of mainproject * @param inclusionLists * inclusion filters of mainproject * @param exclusionLists * exclusion filters of mainproject */ public void createBuild(List<String> srcDirs, List<String> classDirs, List<List<String>> inclusionLists, List<List<String>> exclusionLists) throws JavaModelException { // <target name="build" depends="build-subprojects,build-project"/> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "build"); //$NON-NLS-1$ element.setAttribute("depends", "build-subprojects,build-project"); //$NON-NLS-1$ //$NON-NLS-2$ root.appendChild(element); // <target name="build-subprojects"> // <ant antfile="build.xml" dir="${hello.location}" inheritAll="false" target="build-project"/> // </target> element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "build-subprojects"); //$NON-NLS-1$ List<IJavaProject> subProjects = ExportUtil.getClasspathProjectsRecursive(project); for (Iterator<IJavaProject> iterator = subProjects.iterator(); iterator.hasNext();) { IJavaProject subProject = iterator.next(); Element antElement = doc.createElement("ant"); //$NON-NLS-1$ antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$ antElement.setAttribute(IAntCoreConstants.DIR, "${" + subProject.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("target", "build-project"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$ if (CREATE_ECLIPSE_COMPILE_TARGET) { Element propertysetElement = doc.createElement("propertyset"); //$NON-NLS-1$ Element propertyrefElement = doc.createElement("propertyref"); //$NON-NLS-1$ propertyrefElement.setAttribute(IAntCoreConstants.NAME, "build.compiler"); //$NON-NLS-1$ propertysetElement.appendChild(propertyrefElement); antElement.appendChild(propertysetElement); } element.appendChild(antElement); } root.appendChild(element); // Bug 313386 optimization: // Source directories with the same classes directory get only one <javac> tag // Side effect: Eclipse inclusion and exclusion filters apply to the specified source directory. // Ant inclusion and exclusion filters apply to all source directories. // This may lead to unexpected behavior. HashMap<String, List<String>> class2sources = new HashMap<>(); HashMap<String, List<String>> class2includes = new HashMap<>(); HashMap<String, List<String>> class2excludes = new HashMap<>(); for (int i = 0; i < srcDirs.size(); i++) { String srcDir = srcDirs.get(i); if (!EclipseClasspath.isReference(srcDir)) { String classDir = classDirs.get(i); List<String> inclusions = inclusionLists.get(i); List<String> exclusions = exclusionLists.get(i); List<String> list = class2sources.get(classDir); List<String> list2 = class2includes.get(classDir); List<String> list3 = class2excludes.get(classDir); if (list == null) { list = new ArrayList<>(); list2 = new ArrayList<>(); list3 = new ArrayList<>(); class2sources.put(classDir, list); class2includes.put(classDir, list2); class2excludes.put(classDir, list3); } list.add(srcDir); list2.addAll(inclusions); list3.addAll(exclusions); } } // <target name="build-project" depends="init"> // <echo message="${ant.project.name}: ${ant.file}"/> // <javac destdir="classes"> // <src path="src"/> // <include name=""/> // <exclude name=""/> // <classpath refid="project.classpath"/> // </javac> // </target> element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "build-project"); //$NON-NLS-1$ element.setAttribute("depends", "init"); //$NON-NLS-1$ //$NON-NLS-2$ Element echoElement = doc.createElement("echo"); //$NON-NLS-1$ echoElement.setAttribute("message", "${ant.project.name}: ${ant.file}"); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(echoElement); for (int i = 0; i < srcDirs.size(); i++) { String srcDir = srcDirs.get(i); if (!EclipseClasspath.isReference(srcDir)) { String classDir = classDirs.get(i); List<String> sources = class2sources.get(classDir); List<String> inclusions = class2includes.get(classDir); List<String> exclusions = class2excludes.get(classDir); if (sources != null && sources.size() > 1) { // remove list to exclude it from the next iteration class2sources.put(classDir, null); } else if (sources == null) { continue; } Element javacElement = doc.createElement("javac"); //$NON-NLS-1$ javacElement.setAttribute("includeantruntime", "false"); //$NON-NLS-1$ //$NON-NLS-2$ javacElement.setAttribute("destdir", classDir); //$NON-NLS-1$ javacElement.setAttribute("debug", "true"); //$NON-NLS-1$ //$NON-NLS-2$ javacElement.setAttribute("debuglevel", "${debuglevel}"); //$NON-NLS-1$ //$NON-NLS-2$ javacElement.setAttribute("source", "${source}"); //$NON-NLS-1$ //$NON-NLS-2$ javacElement.setAttribute("target", "${target}"); //$NON-NLS-1$ //$NON-NLS-2$ // Bug 313386: <javac> tag with several source directories for (String s : sources) { Element srcElement = doc.createElement("src"); //$NON-NLS-1$ srcElement.setAttribute("path", s); //$NON-NLS-1$ javacElement.appendChild(srcElement); } for (String inclusion : inclusions) { Element includeElement = doc.createElement("include"); //$NON-NLS-1$ includeElement.setAttribute(IAntCoreConstants.NAME, inclusion); javacElement.appendChild(includeElement); } for (String exclusion : exclusions) { Element excludeElement = doc.createElement("exclude"); //$NON-NLS-1$ excludeElement.setAttribute(IAntCoreConstants.NAME, exclusion); javacElement.appendChild(excludeElement); } Element classpathRefElement = doc.createElement("classpath"); //$NON-NLS-1$ classpathRefElement.setAttribute("refid", projectName + ".classpath"); //$NON-NLS-1$ //$NON-NLS-2$ javacElement.appendChild(classpathRefElement); element.appendChild(javacElement); addCompilerBootClasspath(srcDirs, javacElement); } } root.appendChild(element); } /** * Create target build-refprojects which compiles projects which reference current project. */ private void createBuildRef() throws JavaModelException { Set<IJavaProject> refProjects = new TreeSet<>(ExportUtil.getJavaProjectComparator()); IJavaProject[] projects = project.getJavaModel().getJavaProjects(); for (int i = 0; i < projects.length; i++) { List<IJavaProject> subProjects = ExportUtil.getClasspathProjects(projects[i]); for (Iterator<IJavaProject> iter = subProjects.iterator(); iter.hasNext();) { IJavaProject p = iter.next(); if (projectName.equals(p.getProject().getName())) { refProjects.add(projects[i]); } } } // <target name="build-refprojects"> // <ant antfile="build.xml" dir="${hello.location}" target="clean" inheritAll="false"/> // <ant antfile="build.xml" dir="${hello.location}" target="build" inheritAll="false"/> // </target> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "build-refprojects"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.DESCRIPTION, "Build all projects which " + //$NON-NLS-1$ "reference this project. Useful to propagate changes."); //$NON-NLS-1$ for (Iterator<IJavaProject> iter = refProjects.iterator(); iter.hasNext();) { IJavaProject p = iter.next(); String location = p.getProject().getName() + ".location"; //$NON-NLS-1$ String refProjectRoot = ExportUtil.getProjectRoot(p); String relativePath = ExportUtil.getRelativePath(refProjectRoot, projectRoot); variable2valueMap.put(location, relativePath); Element antElement = doc.createElement("ant"); //$NON-NLS-1$ antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$ antElement.setAttribute(IAntCoreConstants.DIR, "${" + p.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("target", "clean"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(antElement); antElement = doc.createElement("ant"); //$NON-NLS-1$ antElement.setAttribute("antfile", BUILD_XML); //$NON-NLS-1$ antElement.setAttribute(IAntCoreConstants.DIR, "${" + p.getProject().getName() + ".location}"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("target", "build"); //$NON-NLS-1$ //$NON-NLS-2$ antElement.setAttribute("inheritAll", "false"); //$NON-NLS-1$ //$NON-NLS-2$ if (CREATE_ECLIPSE_COMPILE_TARGET) { Element propertysetElement = doc.createElement("propertyset"); //$NON-NLS-1$ Element propertyrefElement = doc.createElement("propertyref"); //$NON-NLS-1$ propertyrefElement.setAttribute(IAntCoreConstants.NAME, "build.compiler"); //$NON-NLS-1$ propertysetElement.appendChild(propertyrefElement); antElement.appendChild(propertysetElement); } element.appendChild(antElement); } root.appendChild(element); } /** * Add target to initialize Eclipse compiler. It copies required jars to ant lib directory. */ public void addInitEclipseCompiler() { // use ECLIPSE_HOME classpath variable IPath value = JavaCore.getClasspathVariable("ECLIPSE_HOME"); //$NON-NLS-1$ if (value != null) { variable2valueMap.put("ECLIPSE_HOME", ExportUtil.getRelativePath( //$NON-NLS-1$ value.toString(), projectRoot)); } // <target name="init-eclipse-compiler" description="copy Eclipse compiler jars to ant lib directory"> // <property name="ECLIPSE_HOME" value="C:/Programme/eclipse-3.1" /> // <copy todir="${ant.library.dir}"> // <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" /> // </copy> // <unzip dest="${ant.library.dir}"> // <patternset includes="jdtCompilerAdapter.jar" /> // <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" /> // </unzip> // </target> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "init-eclipse-compiler"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.DESCRIPTION, "copy Eclipse compiler jars to ant lib directory"); //$NON-NLS-1$ Element copyElement = doc.createElement("copy"); //$NON-NLS-1$ copyElement.setAttribute("todir", "${ant.library.dir}"); //$NON-NLS-1$ //$NON-NLS-2$ Element filesetElement = doc.createElement("fileset"); //$NON-NLS-1$ filesetElement.setAttribute(IAntCoreConstants.DIR, "${ECLIPSE_HOME}/plugins"); //$NON-NLS-1$ filesetElement.setAttribute("includes", "org.eclipse.jdt.core_*.jar"); //$NON-NLS-1$ //$NON-NLS-2$ copyElement.appendChild(filesetElement); element.appendChild(copyElement); Element unzipElement = doc.createElement("unzip"); //$NON-NLS-1$ unzipElement.setAttribute("dest", "${ant.library.dir}"); //$NON-NLS-1$ //$NON-NLS-2$ Element patternsetElement = doc.createElement("patternset"); //$NON-NLS-1$ patternsetElement.setAttribute("includes", "jdtCompilerAdapter.jar"); //$NON-NLS-1$ //$NON-NLS-2$ unzipElement.appendChild(patternsetElement); unzipElement.appendChild(filesetElement.cloneNode(false)); element.appendChild(unzipElement); root.appendChild(element); } /** * Add target to compile project using Eclipse compiler. */ public void addBuildEclipse() { // <target name="build-eclipse-compiler" description="compile project with Eclipse compiler"> // <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" /> // <antcall target="build" /> // </target> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "build-eclipse-compiler"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.DESCRIPTION, "compile project with Eclipse compiler"); //$NON-NLS-1$ Element propertyElement = doc.createElement("property"); //$NON-NLS-1$ propertyElement.setAttribute(IAntCoreConstants.NAME, "build.compiler"); //$NON-NLS-1$ propertyElement.setAttribute(IAntCoreConstants.VALUE, "org.eclipse.jdt.core.JDTCompilerAdapter"); //$NON-NLS-1$ element.appendChild(propertyElement); Element antcallElement = doc.createElement("antcall"); //$NON-NLS-1$ antcallElement.setAttribute("target", "build"); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(antcallElement); root.appendChild(element); } /** * Add all bootclasspaths in srcDirs to given javacElement. */ private void addCompilerBootClasspath(List<String> srcDirs, Element javacElement) { // <bootclasspath> // <path refid="mylib.bootclasspath"/> // <fileset dir="${java.home}/lib" includes="*.jar"/> // <fileset dir="${java.home}/lib/ext" includes="*.jar"/> // </bootclasspath> Element bootclasspathElement = doc.createElement("bootclasspath"); //$NON-NLS-1$ boolean bootclasspathUsed = false; for (Iterator<String> iter = srcDirs.iterator(); iter.hasNext();) { String entry = iter.next(); if (EclipseClasspath.isUserSystemLibraryReference(entry)) { Element pathElement = doc.createElement("path"); //$NON-NLS-1$ pathElement.setAttribute("refid", ExportUtil.removePrefixAndSuffix(entry, "${", "}")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ bootclasspathElement.appendChild(pathElement); bootclasspathUsed = true; } else if (EclipseClasspath.isJreReference(entry)) { addJre(bootclasspathElement); } } if (bootclasspathUsed) { javacElement.appendChild(bootclasspathElement); } } /** * Add run targets. * * @throws CoreException * thrown if problem accessing the launch configuration * @throws TransformerFactoryConfigurationError * thrown if applet file could not get created * @throws UnsupportedEncodingException * thrown if applet file could not get created */ public void createRun() throws CoreException, TransformerFactoryConfigurationError, UnsupportedEncodingException { // <target name="run"> // <java fork="yes" classname="class" failonerror="true" dir="." newenvironment="true"> // <env key="a" value="b"/> // <jvmarg value="-Dx=y"/> // <arg value="arg"/> // <classpath refid="project.classpath"/> // </java> // </target> ILaunchConfiguration[] confs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(); boolean junitUsed = false; for (int i = 0; i < confs.length; i++) { ILaunchConfiguration conf = confs[i]; if (!projectName.equals(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, IAntCoreConstants.EMPTY_STRING))) { continue; } if (conf.getType().getIdentifier().equals(IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION)) { addJavaApplication(variable2valueMap, conf); } else if (conf.getType().getIdentifier().equals(IJavaLaunchConfigurationConstants.ID_JAVA_APPLET)) { addApplet(variable2valueMap, conf); } else if (conf.getType().getIdentifier().equals("org.eclipse.jdt.junit.launchconfig" /* JUnitLaunchConfiguration.ID_JUNIT_APPLICATION */)) //$NON-NLS-1$ { addJUnit(variable2valueMap, conf); junitUsed = true; } } if (junitUsed) { addJUnitReport(); } } /** * Convert Java application launch configuration to ant target and add it to a document. * * @param variable2value * adds Eclipse variables to this map, if run configuration makes use of this feature * @param conf * Java application launch configuration */ public void addJavaApplication(Map<String, String> variable2value, ILaunchConfiguration conf) throws CoreException { Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, conf.getName()); Element javaElement = doc.createElement("java"); //$NON-NLS-1$ javaElement.setAttribute("fork", "yes"); //$NON-NLS-1$ //$NON-NLS-2$ javaElement.setAttribute("classname", conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, IAntCoreConstants.EMPTY_STRING)); //$NON-NLS-1$ javaElement.setAttribute("failonerror", "true"); //$NON-NLS-1$ //$NON-NLS-2$ String dir = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, IAntCoreConstants.EMPTY_STRING); ExportUtil.addVariable(variable2value, dir, projectRoot); if (!dir.equals(IAntCoreConstants.EMPTY_STRING)) { javaElement.setAttribute(IAntCoreConstants.DIR, ExportUtil.getRelativePath(dir, projectRoot)); } if (!conf.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true)) { javaElement.setAttribute("newenvironment", "true"); //$NON-NLS-1$ //$NON-NLS-2$ } Map<String, String> props = conf.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, new TreeMap<String, String>()); addElements(props, doc, javaElement, "env", "key", IAntCoreConstants.VALUE); //$NON-NLS-1$ //$NON-NLS-2$ addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "jvmarg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$ addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "arg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(javaElement); addRuntimeClasspath(conf, javaElement); addRuntimeBootClasspath(conf, javaElement); root.appendChild(element); } /** * Convert applet launch configuration to Ant target and add it to a document. * * @param variable2value * adds Eclipse variables to this map, if run configuration makes use of this feature * @param conf * applet configuration * @throws CoreException * thrown if problem dealing with launch configuration or underlying resources * @throws TransformerFactoryConfigurationError * thrown if applet file could not get created * @throws UnsupportedEncodingException * thrown if applet file could not get created */ public void addApplet(Map<String, String> variable2value, ILaunchConfiguration conf) throws CoreException, TransformerFactoryConfigurationError, UnsupportedEncodingException { String dir = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, IAntCoreConstants.EMPTY_STRING); if (dir.equals(IAntCoreConstants.EMPTY_STRING)) { dir = projectRoot; } ExportUtil.addVariable(variable2value, dir, projectRoot); String value; try { value = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(dir); } catch (CoreException e) { // cannot resolve variable value = null; } String htmlfile = ((value != null) ? value : dir) + '/' + conf.getName() + ".html"; //$NON-NLS-1$ // confirm overwrite if (ExportUtil.existsUserFile(htmlfile) && !MessageDialog.openConfirm(shell, DataTransferMessages.AntBuildfileExportPage_4, DataTransferMessages.AntBuildfileExportPage_4 + ": " + htmlfile)) //$NON-NLS-1$ { return; } IJavaProject javaProject = ExportUtil.getJavaProjectByName(projectName); IFile file = javaProject.getProject().getFile(conf.getName() + ".html"); //$NON-NLS-1$ if (ExportUtil.validateEdit(shell, file)) // checkout file if required { // write build file String html = AppletUtil.buildHTMLFile(conf); InputStream is = new ByteArrayInputStream(html.getBytes("UTF-8")); //$NON-NLS-1$ if (file.exists()) { file.setContents(is, true, true, null); } else { file.create(is, true, null); } } Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, conf.getName()); Element javaElement = doc.createElement("java"); //$NON-NLS-1$ javaElement.setAttribute("fork", "yes"); //$NON-NLS-1$//$NON-NLS-2$ javaElement.setAttribute("classname", conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_APPLET_APPLETVIEWER_CLASS, "sun.applet.AppletViewer")); //$NON-NLS-1$ //$NON-NLS-2$ javaElement.setAttribute("failonerror", "true"); //$NON-NLS-1$ //$NON-NLS-2$ if (value != null) { javaElement.setAttribute(IAntCoreConstants.DIR, ExportUtil.getRelativePath(dir, projectRoot)); } addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "jvmarg", "line", variable2value, projectRoot); //$NON-NLS-1$//$NON-NLS-2$ addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, javaElement, "arg", "line", variable2value, projectRoot); //$NON-NLS-1$//$NON-NLS-2$ addElement(conf.getName() + ".html", doc, javaElement, "arg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ element.appendChild(javaElement); addRuntimeClasspath(conf, javaElement); addRuntimeBootClasspath(conf, javaElement); root.appendChild(element); } /** * Convert JUnit launch configuration to JUnit task and add it to a document. * * @param variable2value * adds Eclipse variables to this map, if run configuration makes use of this feature * @param conf * applet configuration */ public void addJUnit(Map<String, String> variable2value, ILaunchConfiguration conf) throws CoreException { // <target name="runtest"> // <mkdir dir="junit"/> // <junit fork="yes" printsummary="withOutAndErr"> // <formatter type="xml"/> // <test name="testclass"/> // <env key="a" value="b"/> // <jvmarg value="-Dx=y"/> // <classpath refid="project.classpath"/> // </junit> // </target> String testClass = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, IAntCoreConstants.EMPTY_STRING); Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, conf.getName()); Element mkdirElement = doc.createElement("mkdir"); //$NON-NLS-1$ mkdirElement.setAttribute(IAntCoreConstants.DIR, "${junit.output.dir}"); //$NON-NLS-1$ element.appendChild(mkdirElement); Element junitElement = doc.createElement("junit"); //$NON-NLS-1$ junitElement.setAttribute("fork", "yes"); //$NON-NLS-1$ //$NON-NLS-2$ junitElement.setAttribute("printsummary", "withOutAndErr"); //$NON-NLS-1$ //$NON-NLS-2$ String dir = conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, IAntCoreConstants.EMPTY_STRING); ExportUtil.addVariable(variable2value, dir, projectRoot); if (!dir.equals(IAntCoreConstants.EMPTY_STRING)) { junitElement.setAttribute(IAntCoreConstants.DIR, ExportUtil.getRelativePath(dir, projectRoot)); } if (!conf.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true)) { junitElement.setAttribute("newenvironment", "true"); //$NON-NLS-1$ //$NON-NLS-2$ } Element formatterElement = doc.createElement("formatter"); //$NON-NLS-1$ formatterElement.setAttribute("type", "xml"); //$NON-NLS-1$//$NON-NLS-2$ junitElement.appendChild(formatterElement); if (!testClass.equals(IAntCoreConstants.EMPTY_STRING)) { // Case 1: Single JUnit class Element testElement = doc.createElement("test"); //$NON-NLS-1$ testElement.setAttribute(IAntCoreConstants.NAME, testClass); testElement.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$ junitElement.appendChild(testElement); } else { // Case 2: Run all tests in project, package or source folder String container = conf.getAttribute("org.eclipse.jdt.junit.CONTAINER" /* JUnitBaseLaunchConfiguration.LAUNCH_CONTAINER_ATTR */, IAntCoreConstants.EMPTY_STRING); //$NON-NLS-1$ IType[] types = ExportUtil.findTestsInContainer(container); Set<IType> sortedTypes = new TreeSet<>(ExportUtil.getITypeComparator()); sortedTypes.addAll(Arrays.asList(types)); for (Iterator<IType> iter = sortedTypes.iterator(); iter.hasNext();) { IType type = iter.next(); Element testElement = doc.createElement("test"); //$NON-NLS-1$ testElement.setAttribute(IAntCoreConstants.NAME, type.getFullyQualifiedName()); testElement.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$ junitElement.appendChild(testElement); } } Map<String, String> props = conf.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, new TreeMap<String, String>()); addElements(props, doc, junitElement, "env", "key", IAntCoreConstants.VALUE); //$NON-NLS-1$ //$NON-NLS-2$ addElement(conf.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, IAntCoreConstants.EMPTY_STRING), doc, junitElement, "jvmarg", "line", variable2value, projectRoot); //$NON-NLS-1$ //$NON-NLS-2$ element.appendChild(junitElement); addRuntimeClasspath(conf, junitElement); addRuntimeBootClasspath(conf, junitElement); root.appendChild(element); } /** * Add junitreport target. */ public void addJUnitReport() { variable2valueMap.put("junit.output.dir", JUNIT_OUTPUT_DIR); //$NON-NLS-1$ // <target name="junitreport"> // <junitreport todir="junit"> // <fileset dir="junit"> // <include name="TEST-*.xml"/> // </fileset> // <report format="frames" todir="junit"/> // </junitreport> // </target> Element element = doc.createElement("target"); //$NON-NLS-1$ element.setAttribute(IAntCoreConstants.NAME, "junitreport"); //$NON-NLS-1$ Element junitreport = doc.createElement("junitreport"); //$NON-NLS-1$ junitreport.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$ Element fileset = doc.createElement("fileset"); //$NON-NLS-1$ fileset.setAttribute(IAntCoreConstants.DIR, "${junit.output.dir}"); //$NON-NLS-1$ junitreport.appendChild(fileset); Element include = doc.createElement("include"); //$NON-NLS-1$ include.setAttribute(IAntCoreConstants.NAME, "TEST-*.xml"); //$NON-NLS-1$ fileset.appendChild(include); Element report = doc.createElement("report"); //$NON-NLS-1$ report.setAttribute("format", "frames"); //$NON-NLS-1$ //$NON-NLS-2$ report.setAttribute("todir", "${junit.output.dir}"); //$NON-NLS-1$ //$NON-NLS-2$ junitreport.appendChild(report); element.appendChild(junitreport); root.appendChild(element); } /** * Add classpath tag to given javaElement. */ private void addRuntimeClasspath(ILaunchConfiguration conf, Element javaElement) throws CoreException { // <classpath refid="hello.classpath"/> Element classpathRefElement = doc.createElement("classpath"); //$NON-NLS-1$ EclipseClasspath runtimeClasspath = new EclipseClasspath(project, conf, false); if (ExportUtil.isDefaultClasspath(project, runtimeClasspath)) { classpathRefElement.setAttribute("refid", projectName + ".classpath"); //$NON-NLS-1$ //$NON-NLS-2$ } else { String pathId = "run." + conf.getName() + ".classpath"; //$NON-NLS-1$ //$NON-NLS-2$ classpathRefElement.setAttribute("refid", pathId); //$NON-NLS-1$ createClasspaths(pathId, project, runtimeClasspath); } javaElement.appendChild(classpathRefElement); } /** * Add bootclasspath tag to given javaElement. */ private void addRuntimeBootClasspath(ILaunchConfiguration conf, Element javaElement) throws CoreException { // <bootclasspath> // <path refid="run.hello.bootclasspath"/> // </bootclasspath> EclipseClasspath bootClasspath = new EclipseClasspath(project, conf, true); if (bootClasspath.rawClassPathEntries.size() == 1 && EclipseClasspath.isJreReference(bootClasspath.rawClassPathEntries.get(0))) { // the default boot classpath contains exactly one element (the JRE) return; } String pathId = "run." + conf.getName() + ".bootclasspath"; //$NON-NLS-1$ //$NON-NLS-2$ createClasspaths(pathId, project, bootClasspath); Element bootclasspath = doc.createElement("bootclasspath"); //$NON-NLS-1$ Element classpathRefElement = doc.createElement("path"); //$NON-NLS-1$ classpathRefElement.setAttribute("refid", pathId); //$NON-NLS-1$ bootclasspath.appendChild(classpathRefElement); javaElement.appendChild(bootclasspath); } /** * Create child node from <code>cmdLine</code> and add it to <code>element</code> which is part of <code>doc</code>. * * @param cmdLineArgs * command line arguments, separated with spaces or within double quotes, may also contain Eclipse variables * @param doc * XML document * @param element * node to add child to * @param elementName * name of new child node * @param attributeName * name of attribute for child node * @param variable2valueMap * adds Eclipse variables to this map, if command line makes use of this feature */ private static void addElement(String cmdLineArgs, Document doc, Element element, String elementName, String attributeName, Map<String, String> variable2valueMap, String projectRoot) { if (cmdLineArgs == null || cmdLineArgs.length() == 0) { return; } ExportUtil.addVariable(variable2valueMap, cmdLineArgs, projectRoot); Element itemElement = doc.createElement(elementName); itemElement.setAttribute(attributeName, cmdLineArgs); element.appendChild(itemElement); } /** * Create child nodes from string map and add them to <code>element</code> which is part of <code>doc</code>. * * @param map * key/value string pairs * @param doc * XML document * @param element * node to add children to * @param elementName * name of new child node * @param keyAttributeName * name of key attribute * @param valueAttributeName * name of value attribute */ private static void addElements(Map<String, String> map, Document doc, Element element, String elementName, String keyAttributeName, String valueAttributeName) { for (Iterator<String> iter = map.keySet().iterator(); iter.hasNext();) { String key = iter.next(); String value = map.get(key); Element itemElement = doc.createElement(elementName); itemElement.setAttribute(keyAttributeName, key); itemElement.setAttribute(valueAttributeName, value); element.appendChild(itemElement); } } /** * Set config options. * * @param buildfilename * name for Ant buildfile * @param junitdir * name of JUnit output directory * @param checkcycles * check project for Ant compatibility * @param eclipsecompiler * generate target for compiling project with Eclipse compiler */ public static void setOptions(String buildfilename, String junitdir, boolean checkcycles, boolean eclipsecompiler) { if (buildfilename.length() > 0) { BUILD_XML = buildfilename; } if (junitdir.length() > 0) { JUNIT_OUTPUT_DIR = junitdir; } CHECK_SOURCE_CYCLES = checkcycles; CREATE_ECLIPSE_COMPILE_TARGET = eclipsecompiler; } }